﻿namespace MDXStudio.MdSchema
{
    using Microsoft.AnalysisServices.AdomdClient;
    using System;
    using System.Data;
    using System.Windows.Forms;

    internal class MdTreeBuilder
    {
        private const string cChildrenPlaceholder = "__CHILDREN_PLACEHOLDER_";
        private const string cChildrenPlaceholderHierarchy = "__CHILDREN_PLACEHOLDER_HIER__";
        private const string cChildrenPlaceholderLevel = "__CHILDREN_PLACEHOLDER_LVL__";
        private const string cChildrenPlaceholderMembers = "__CHILDREN_PLACEHOLDER_MEMB__";
        private AdomdConnection mConn;
        private int mMaxMemberCount = 100;
        private eServerVersion mServerVersion;
        private bool mShowHiddenObjects;

        private void AddDimensionsNodes(TreeNode pCubeNode)
        {
            AdomdRestrictionCollection pRestrictions = new AdomdRestrictionCollection();
            pRestrictions.Add("CUBE_NAME", ((MdCube) pCubeNode.Tag).Name);
            if (this.mServerVersion >= eServerVersion.Yukon)
            {
                pRestrictions.Add("DIMENSION_VISIBILITY", 3);
            }
            DataView view = new DataView(this.GetSchemaDataTable(AdomdSchemaGuid.Dimensions, pRestrictions), null, "DIMENSION_CAPTION", DataViewRowState.CurrentRows);
            foreach (DataRow row in view.ToTable().Rows)
            {
                MdDimension dimension = new MdDimension(row);
                if (dimension.DimensionType != eDimensionType.Measure)
                {
                    string imageKey = "Dimension.ico";
                    if (!dimension.IsVisible)
                    {
                        imageKey = imageKey + "_BW";
                    }
                    TreeNode pNode = pCubeNode.Nodes.Add(dimension.UniqueName, dimension.Caption, imageKey, imageKey);
                    pNode.Tag = dimension;
                    this.AddDummyNode(pNode, "__CHILDREN_PLACEHOLDER_HIER__");
                }
            }
        }

        private void AddDummyNode(TreeNode pNode, string pPlaceholder)
        {
            pNode.Nodes.Add(pPlaceholder);
        }

        private void AddHierarchiesNodes(TreeNode pDimensionNode)
        {
            AdomdRestrictionCollection pRestrictions = new AdomdRestrictionCollection();
            MdDimension tag = (MdDimension) pDimensionNode.Tag;
            pRestrictions.Add("CUBE_NAME", tag.CubeName);
            pRestrictions.Add("DIMENSION_UNIQUE_NAME", tag.UniqueName);
            if (this.mServerVersion >= eServerVersion.Yukon)
            {
                pRestrictions.Add("HIERARCHY_VISIBILITY", 3);
            }
            DataTable schemaDataTable = this.GetSchemaDataTable(AdomdSchemaGuid.Hierarchies, pRestrictions);
            DataView view = (this.mServerVersion >= eServerVersion.Yukon) ? new DataView(schemaDataTable, null, "HIERARCHY_DISPLAY_FOLDER, HIERARCHY_CAPTION", DataViewRowState.CurrentRows) : new DataView(schemaDataTable, null, "HIERARCHY_CAPTION", DataViewRowState.CurrentRows);
            foreach (DataRow row in view.ToTable().Rows)
            {
                string str;
                TreeNode node;
                MdHierarchy hierarchy = new MdHierarchy(row);
                switch (hierarchy.Origin)
                {
                    case eHierarchyOrigin.UserDefined:
                        str = "Hierarchy.ico";
                        break;

                    case eHierarchyOrigin.SystemEnabled:
                        str = "AttributeHierarchy.ico";
                        break;

                    case eHierarchyOrigin.ParentChild:
                        str = "ParentChild.ico";
                        break;

                    case eHierarchyOrigin.Key:
                        str = "AttributeKey.ico";
                        break;

                    default:
                        str = "AttributeHierarchy.ico";
                        break;
                }
                if (!hierarchy.IsVisible)
                {
                    str = str + "_BW";
                }
                if (!string.IsNullOrEmpty(hierarchy.DisplayFolder))
                {
                    string displayFolder = hierarchy.DisplayFolder;
                    TreeNode[] nodeArray = pDimensionNode.Nodes.Find(displayFolder, false);
                    TreeNode node2 = null;
                    if (nodeArray.Length == 0)
                    {
                        node2 = pDimensionNode.Nodes.Add(displayFolder, displayFolder);
                        node2.ImageKey = "FolderClosed.ico";
                        node2.SelectedImageKey = "FolderOpen.ico";
                    }
                    else
                    {
                        node2 = nodeArray[0];
                    }
                    node = node2.Nodes.Add(hierarchy.UniqueName, hierarchy.Caption, str, str);
                }
                else
                {
                    node = pDimensionNode.Nodes.Add(hierarchy.UniqueName, hierarchy.Caption, str, str);
                }
                node.Tag = hierarchy;
                this.AddDummyNode(node, "__CHILDREN_PLACEHOLDER_LVL__");
            }
        }

        private void AddKpisNodes(TreeNode pCubeNode)
        {
            TreeNode lParentNode = pCubeNode.Nodes.Add("Kpis", "Kpis", "Kpi.ico", "Kpi.ico");
            AdomdRestrictionCollection pRestrictions = new AdomdRestrictionCollection();
            pRestrictions.Add("CUBE_NAME", ((MdCube) pCubeNode.Tag).Name);
            DataView view = new DataView(this.GetSchemaDataTable(AdomdSchemaGuid.Kpis, pRestrictions), null, "KPI_CAPTION", DataViewRowState.CurrentRows);
            foreach (DataRow row in view.ToTable().Rows)
            {
                MdKpi kpi = new MdKpi(row);
                string imageKey = "Kpi.ico";
                string displayFolder = kpi.DisplayFolder;
                if (string.IsNullOrEmpty(displayFolder))
                {
                    displayFolder = kpi.MeasureGroupName;
                }
                if (!string.IsNullOrEmpty(displayFolder))
                {
                    foreach (TreeNode node3 in this.BuildDisplayFolderNode(lParentNode, displayFolder))
                    {
                        node3.Nodes.Add(kpi.UniqueName, kpi.Caption, imageKey, imageKey).Tag = kpi;
                    }
                }
                else
                {
                    lParentNode.Nodes.Add(kpi.UniqueName, kpi.Caption, imageKey, imageKey).Tag = kpi;
                }
            }
        }

        private void AddLelvelsNodes(TreeNode pHierarchyNode)
        {
            MdHierarchy tag = (MdHierarchy) pHierarchyNode.Tag;
            AdomdRestrictionCollection pRestrictions = new AdomdRestrictionCollection();
            pRestrictions.Add("CUBE_NAME", tag.CubeName);
            pRestrictions.Add("DIMENSION_UNIQUE_NAME", tag.DimensionUniqueName);
            pRestrictions.Add("HIERARCHY_UNIQUE_NAME", tag.UniqueName);
            if (this.mServerVersion >= eServerVersion.Yukon)
            {
                pRestrictions.Add("LEVEL_VISIBILITY", 3);
            }
            foreach (DataRow row in this.GetSchemaDataTable(AdomdSchemaGuid.Levels, pRestrictions).Rows)
            {
                MdLevel level = new MdLevel(row);
                string imageKey = "Level" + ((level.Number + 1)).ToString() + ".ico";
                if (!level.IsVisible)
                {
                    imageKey = imageKey + "_BW";
                }
                TreeNode pNode = pHierarchyNode.Nodes.Add(level.UniqueName, level.Caption, imageKey, imageKey);
                pNode.Tag = level;
                this.AddDummyNode(pNode, "__CHILDREN_PLACEHOLDER_MEMB__");
            }
        }

        private void AddMeasuresNodes(TreeNode pCubeNode)
        {
            TreeNode lParentNode = pCubeNode.Nodes.Add("Measures", "Measures", "Measure.ico", "Measure.ico");
            AdomdRestrictionCollection pRestrictions = new AdomdRestrictionCollection();
            pRestrictions.Add("CUBE_NAME", ((MdCube) pCubeNode.Tag).Name);
            if (this.mServerVersion >= eServerVersion.Yukon)
            {
                pRestrictions.Add("MEASURE_VISIBILITY", 3);
            }
            DataTable schemaDataTable = this.GetSchemaDataTable(AdomdSchemaGuid.Measures, pRestrictions);
            DataView view = (this.mServerVersion >= eServerVersion.Yukon) ? new DataView(schemaDataTable, null, "MEASUREGROUP_NAME, MEASURE_CAPTION", DataViewRowState.CurrentRows) : new DataView(schemaDataTable, null, "MEASURE_CAPTION", DataViewRowState.CurrentRows);
            foreach (DataRow row in view.ToTable().Rows)
            {
                MdMeasure measure = new MdMeasure(row);
                string imageKey = string.IsNullOrEmpty(measure.Expression) ? "Measure.ico" : "MeasureCalculated.ico";
                if (!measure.IsVisible)
                {
                    imageKey = imageKey + "_BW";
                }
                string displayFolder = measure.DisplayFolder;
                if (string.IsNullOrEmpty(displayFolder))
                {
                    displayFolder = measure.MeasureGroupName;
                }
                if (!string.IsNullOrEmpty(displayFolder))
                {
                    foreach (TreeNode node3 in this.BuildDisplayFolderNode(lParentNode, displayFolder))
                    {
                        node3.Nodes.Add(measure.UniqueName, measure.Caption, imageKey, imageKey).Tag = measure;
                    }
                }
                else
                {
                    lParentNode.Nodes.Add(measure.UniqueName, measure.Caption, imageKey, imageKey).Tag = measure;
                }
            }
        }

        private void AddMembersNodes(TreeNode pNode)
        {
            string str;
            string cubeName;
            if (pNode.Tag is MdLevel)
            {
                MdLevel tag = (MdLevel) pNode.Tag;
                str = string.Format("{0}.Members", tag.UniqueName);
                cubeName = tag.CubeName;
            }
            else if (pNode.Tag is MdMember)
            {
                MdMember member = (MdMember) pNode.Tag;
                str = string.Format("{0}.Children", member.UniqueName);
                cubeName = member.CubeName;
            }
            else
            {
                return;
            }
            AdomdCommand command = new AdomdCommand(string.Format("SELECT HEAD({0}, {1}) \r\nPROPERTIES MEMBER_KEY, PARENT_UNIQUE_NAME, PARENT_LEVEL, DIMENSION_UNIQUE_NAME, HIERARCHY_UNIQUE_NAME, CUBE_NAME on 0, \r\n{{}} on 1 \r\nFROM [{2}]", str, this.mMaxMemberCount, cubeName), this.mConn);
            PositionCollection positions = command.ExecuteCellSet().Axes[0].Positions;
            PositionCollection.Enumerator enumerator = positions.GetEnumerator();
            while (enumerator.MoveNext())
            {
                Position current = enumerator.Current;
                MdMember member2 = MdMember.CreateFromMember(current.Members[0]);
                TreeNode node = pNode.Nodes.Add(member2.UniqueName, member2.Name, "Member.ico", "Member.ico");
                node.Tag = member2;
                if (member2.HasChildren)
                {
                    this.AddDummyNode(node, "__CHILDREN_PLACEHOLDER_MEMB__");
                }
            }
            if (positions.Count >= this.mMaxMemberCount)
            {
                pNode.Nodes.Add("...", "...", "Member.ico", "Member.ico");
            }
        }

        private void AddSetsNodes(TreeNode pCubeNode)
        {
            TreeNode lParentNode = pCubeNode.Nodes.Add("NamedSets", "Named Sets", "NamedSet.ico", "NamedSet.ico");
            AdomdRestrictionCollection pRestrictions = new AdomdRestrictionCollection();
            pRestrictions.Add("CUBE_NAME", ((MdCube) pCubeNode.Tag).Name);
            DataView view = new DataView(this.GetSchemaDataTable(AdomdSchemaGuid.Sets, pRestrictions), null, "SET_CAPTION", DataViewRowState.CurrentRows);
            foreach (DataRow row in view.ToTable().Rows)
            {
                MdSet set = new MdSet(row);
                string imageKey = "NamedSet.ico";
                string displayFolder = set.DisplayFolder;
                if (!string.IsNullOrEmpty(displayFolder))
                {
                    foreach (TreeNode node3 in this.BuildDisplayFolderNode(lParentNode, displayFolder))
                    {
                        node3.Nodes.Add(set.UniqueName, set.Caption, imageKey, imageKey).Tag = set;
                    }
                }
                else
                {
                    lParentNode.Nodes.Add(set.UniqueName, set.Caption, imageKey, imageKey).Tag = set;
                }
            }
        }

        private TreeNode[] BuildDisplayFolderNode(TreeNode lParentNode, string lDisplayFolder)
        {
            string[] strArray = lDisplayFolder.Split(new char[] { ';' });
            TreeNode[] nodeArray = new TreeNode[strArray.Length];
            int num = 0;
            foreach (string str in strArray)
            {
                string[] strArray2 = str.Split(new char[] { '\\' });
                TreeNode node = lParentNode;
                foreach (string str2 in strArray2)
                {
                    TreeNode[] nodeArray2 = node.Nodes.Find(str2, false);
                    if (nodeArray2.Length == 0)
                    {
                        node = node.Nodes.Add(str2, str2);
                        node.ImageKey = "FolderClosed.ico";
                        node.SelectedImageKey = "FolderOpen.ico";
                    }
                    else
                    {
                        node = nodeArray2[0];
                    }
                }
                nodeArray[num++] = node;
            }
            return nodeArray;
        }

        public void ExpandNode(TreeNode pNode)
        {
            if (pNode.Nodes.Count != 0)
            {
                string text = pNode.Nodes[0].Text;
                if (text.StartsWith("__CHILDREN_PLACEHOLDER_", StringComparison.Ordinal))
                {
                    pNode.Nodes.Clear();
                    string str2 = text;
                    if (str2 != null)
                    {
                        if (!(str2 == "__CHILDREN_PLACEHOLDER_HIER__"))
                        {
                            if (!(str2 == "__CHILDREN_PLACEHOLDER_LVL__"))
                            {
                                if (str2 == "__CHILDREN_PLACEHOLDER_MEMB__")
                                {
                                    this.AddMembersNodes(pNode);
                                }
                            }
                            else
                            {
                                this.AddLelvelsNodes(pNode);
                            }
                        }
                        else
                        {
                            this.AddHierarchiesNodes(pNode);
                        }
                    }
                }
            }
        }

        private Version GetOlapServerVersion()
        {
            AdomdRestrictionCollection restrictions = new AdomdRestrictionCollection();
            restrictions.Add(new AdomdRestriction("PropertyName", "DBMSVersion"));
            return new Version((string) this.mConn.GetSchemaDataSet("DISCOVER_PROPERTIES", restrictions).Tables[0].Rows[0]["Value"]);
        }

        private DataTable GetSchemaDataTable(Guid pSchemaGuid, AdomdRestrictionCollection pRestrictions)
        {
            if (pRestrictions == null)
            {
                pRestrictions = new AdomdRestrictionCollection();
            }
            if (this.mShowHiddenObjects && (this.mServerVersion >= eServerVersion.Yukon))
            {
                pRestrictions.Add("CUBE_SOURCE", 0);
            }
            return this.mConn.GetSchemaDataSet(AdomdSchema.sSchemaList[pSchemaGuid].Id, pRestrictions, 1).Tables[0];
        }

        public void RebuidTree(TreeView pTreeView, string pCubeName)
        {
            TreeNodeCollection nodes = pTreeView.Nodes;
            nodes.Clear();
            if ((this.mConn != null) && (this.mConn.State == ConnectionState.Open))
            {
                AdomdRestrictionCollection pRestrictions = new AdomdRestrictionCollection();
                pRestrictions.Add("CUBE_NAME", pCubeName);
                MdCube cube = new MdCube(this.GetSchemaDataTable(AdomdSchemaGuid.Cubes, pRestrictions).Rows[0]);
                TreeNode pCubeNode = nodes.Add("[" + cube.UniqueName + "]", cube.Caption, "Cube.ico");
                pCubeNode.Tag = cube;
                this.AddMeasuresNodes(pCubeNode);
                this.AddSetsNodes(pCubeNode);
                this.AddKpisNodes(pCubeNode);
                this.AddDimensionsNodes(pCubeNode);
                pCubeNode.Expand();
            }
        }

        public AdomdConnection Conn
        {
            get
            {
                return this.mConn;
            }
            set
            {
                this.mConn = value;
                switch (this.GetOlapServerVersion().Major)
                {
                    case 8:
                        this.mServerVersion = eServerVersion.Shiloh;
                        return;

                    case 9:
                        this.mServerVersion = eServerVersion.Yukon;
                        return;

                    case 10:
                        this.mServerVersion = eServerVersion.Katmai;
                        return;
                }
                this.mServerVersion = eServerVersion.Unknown;
            }
        }

        public int MaxMemberCount
        {
            get
            {
                return this.mMaxMemberCount;
            }
            set
            {
                this.mMaxMemberCount = value;
            }
        }

        public bool ShowHiddenObjects
        {
            get
            {
                return this.mShowHiddenObjects;
            }
            set
            {
                this.mShowHiddenObjects = value;
            }
        }
    }
}

